﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;



namespace Kernelx.Extensions
{
    /// <summary>
    /// 
    /// </summary>
    public static class DefiniteTypeExtensions
    {
        #region  扩展 PropertyInfo
        /// <summary>
        /// 简化操作pi.GetIndexParameters().Select(n => n.DefaultValue).ToArray()
        /// </summary>
        /// <param name="pi"></param>
        /// <returns></returns>
        public static object[] GetIndexValues(this PropertyInfo pi)
        {
            return pi.GetIndexParameters().Select(n => n.DefaultValue).ToArray();
        }


        #endregion


        #region 扩展 Type 

        /// <summary>
        /// 
        /// </summary>
        /// <param name="targetType"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static LambdaExpression GetMemberExpression(this Type targetType, string propertyName)
        {
            var parameter = Expression.Parameter(targetType, "p");
            var mem = Expression.PropertyOrField(parameter, propertyName);
            var ptype = (mem.Member as PropertyInfo)?.PropertyType;

            var delegateType = typeof(Func<,>).MakeGenericType(new[] { targetType, ptype });
            return Expression.Lambda(delegateType, mem, parameter);
        }


        /// <summary>
        /// 获取指定类型的指定特性实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <param name="inherit"></param>
        /// <returns></returns>
        public static T GetCustomAttribute<T>(this Type type, bool inherit = false) where T : Attribute
            => type.GetCustomAttributes(typeof(T), inherit).FirstOrDefault() as T;


        /// <summary>
        /// 获取指定类型的属性成员名及标记的<typeparamref name="TAttribute"/>信息集合
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <param name="inherit"></param>
        /// <returns></returns>
        public static IEnumerable<KeyValuePair<string, TAttribute>> GetMemberPairs<TAttribute>(this Type type, bool inherit = false) where TAttribute : Attribute
        {
            IEnumerable<MemberInfo> members = type.IsEnum ? type.GetFields(BindingFlags.Static | BindingFlags.Public).Select(x => x as MemberInfo) : type.GetProperties();
            return members.Select(x => new KeyValuePair<string, TAttribute>(x.Name, x.GetCustomAttributes(typeof(TAttribute), inherit).FirstOrDefault() as TAttribute));
        }

        /// <summary>
        /// 获取类型的默认值
        /// </summary>
        /// <param name="type"></param>
        /// <param name="sign">指定在获取类类型的默认值时如果存在公共无参构造时是否返回构造实例
        /// (引用类型:true表示返回构造实例,false表示返回null)(注:枚举类型的default(type)等于0,该值可能不是有效的枚举项的值.true表示返回有效的枚举项值)
        /// </param>
        /// <returns></returns>
        public static object GetDefaultValue(this Type type, bool sign = false)
        { 
            if (type.IsEnum)
            {
                if (sign)
                {
                    var strs = Enum.GetNames(type);
                    return Enum.Parse(type, strs[0]);
                }
                return Enum.ToObject(type, 0);
            }
            if (type.IsValueType && type.Name != "Nullable`1")
            {

                switch (type.Name.ToLower())
                {

                    case "guid": return default(Guid);
                    case "datetime": return default(DateTime);
                    case "boolean": return default(bool);

                    case "byte": return default(byte);

                    case "uint16": return default(ushort);
                    case "int16": return default(short);

                    case "uint32": return default(uint);

                    case "decimal": return default(decimal);

                    default: return 0;
                }
            }
            if (type.Name.ToLower() == "string")
                return sign ? string.Empty : default;
            ConstructorInfo c;
            if (!sign || (c = type.GetConstructor(Type.EmptyTypes)) == null)
                return null;
            return c.Invoke(new object[0]);
        }


        /// <summary>
        /// 检查类型是否派生是自baseType类型(或继承自BaseType接口类型)
        /// </summary>
        /// <param name="this"></param>
        /// <param name="baseType"></param>
        /// <returns></returns>
        public static bool IsDerived(this Type @this, Type baseType)
        {
            if (baseType != null)
                return @this != baseType && baseType.IsAssignableFrom(@this);
            throw new ArgumentException($"{nameof(baseType)} 不能为null");
        }


        #endregion



        #region  扩展 object

        /// <summary>
        /// 比较俩个值是否相等
        /// </summary>
        /// <param name="l"></param>
        /// <param name="r"></param>
        /// <returns></returns>
        public static bool IsEquals(this object l, object r)
        {
            if (l == null || r == null)
                return l == null & r == null;
            return l.Equals(r);
        }

        /// <summary>
        /// 将<paramref name="value"/>的类型转换成指定<paramref name="type"/>的实例 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static object ConvertTo(this object value, Type type)
        {
            if (type == null)
                throw new ApplicationException($"必须提供指定的类型{nameof(type)}");
            if (value == null || value == DBNull.Value)
                return null;
            if (value.GetType() == type)
                return value;

            var vStr = value?.ToString();

            if (type == typeof(string))
                return vStr;
            else
            {
                if (string.IsNullOrEmpty(vStr))
                    return type.GetDefaultValue();

                if (type == typeof(bool) || type == typeof(bool?))
                {
                    bool rv;
                    if (Regex.IsMatch(vStr, @"^\d+$"))
                        rv = int.Parse(vStr) != 0;
                    else
                        rv = bool.Parse(vStr);

                    if (type.IsGenericType)
                        return new bool?(rv);
                    return rv;
                }
                Type[] generictypes;
                if (type.IsGenericType && (generictypes = type.GetGenericArguments()).Length == 1)
                {
                    var changeType = generictypes[0];
                    object obj;
                    if (changeType.IsEnum)
                        obj = Enum.Parse(changeType, vStr);
                    else
                        obj = System.Convert.ChangeType(value, changeType);

                    return type.GetConstructor(new[] { changeType }).Invoke(new[] { obj });
                }
                else
                {
                    var ctor = type.GetConstructor(new[] { typeof(string) });
                    if (ctor != null)
                        return ctor.Invoke(new[] { value.ToString() });

                    if (type.IsEnum)
                        return Enum.Parse(type, vStr);

                    var marktype = typeof(IEnumerable<>).MakeGenericType(type);
                    if (value.GetType().IsDerived(marktype))
                        return value;

                    return System.Convert.ChangeType(value, type);
                }
            }
            throw new ArgumentException(string.Format("无法将{0}转换成指定类型:{1}", value, type.FullName));
        }

         
        #endregion
         
    }
}
